package org.particles.gui.statistic;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.List;

import javax.swing.JPanel;

import org.particles.common.CommonUtil;

/**
 * draws diagram representing current and old
 * values of an simulation parameter.
 */
public class DiagramPanel extends JPanel {
	private static final long serialVersionUID = -2477513591788659873L;
	private List<Double> statistic;
	/** hold x value of mouse cursor. */
	private int mouseOverX = -1;
	private int startIndex = 0;
	
	public DiagramPanel() {
		// set diagram marker if mouse if moving over
		final MouseMotionAdapter mouseMotionListener = new MouseMotionAdapter() {
			@Override
			public void mouseMoved(MouseEvent evt) {
				mouseOverX = evt.getX();
				final Insets borderInsets = getBorder().getBorderInsets(DiagramPanel.this);
				final int index = mouseOverX - borderInsets.left + startIndex;
				if(index < statistic.size() && index >= 0) {
					setToolTipText(statistic.get(index).toString());
				}
				repaint();
			}
		};
		addMouseMotionListener(mouseMotionListener);
		
		// delete diagram marker if mouse is away
		final MouseAdapter mouseListener = new MouseAdapter() {
			@Override
			public void mouseExited(MouseEvent e) {
				mouseOverX = -1;
				repaint();
			}
		};
		addMouseListener(mouseListener);
	}
	
	@Override
	public void paintComponent(final Graphics g) {
		super.paintComponent(g);
		if(statistic == null || statistic.size() < 1) {
			return;
		}
		// find min and max values
		Double maxValue = Double.MIN_VALUE;
		Double minValue = Double.MAX_VALUE;
		
		// find array start index
		final Dimension dim = getSize();
		final Insets borderInsets = getBorder().getBorderInsets(this);
		final int realPanelWidth = dim.width - borderInsets.left - borderInsets.right;
		final int realPanelHeight = dim.height - borderInsets.top - borderInsets.bottom;
		startIndex = statistic.size() - realPanelWidth;
		if(startIndex < 0) {
			startIndex = 0;
		}
		
		for(int i = startIndex; i < statistic.size(); i++) {
			final double value = statistic.get(i);
			if(value > maxValue) {
				maxValue = value;
			}
			if(value < minValue) {
				minValue = value;
			}
		}
		
		// determine value height
		final double valueHeight;
		if(maxValue == minValue) {
			valueHeight = maxValue;
		}
		else if(minValue < 0 && maxValue > 0) {
			valueHeight = maxValue + Math.abs(minValue);
		}
		else {
			valueHeight = maxValue - minValue;
		}
		
		// determine coef that should be < 0, so we can multiply with it
		double coef = realPanelHeight / valueHeight;
		if(valueHeight > realPanelHeight) {
			coef = 1 / coef;
		}
		
		// determine y1
		double y1;
		if(minValue < 0 && maxValue > 0) {
			y1 = Math.abs(minValue) * coef;
		}
		else if(minValue < 0 && maxValue < 0) {
			y1 = realPanelHeight;
		}
		else {
			y1 = 0;
		}
		y1 = realPanelHeight - y1;
		
		// draw
		int x = borderInsets.left;
		for(int i = startIndex; i < statistic.size(); i++) {
			double y2;
			if(minValue == maxValue) {
				y2 = statistic.get(i) * coef;
			}
			else {
				y2 = (statistic.get(i) - minValue) * coef;
			}
			y2 = realPanelHeight - y2;
			if(x == mouseOverX) {
				g.setColor(Color.RED);
			}
			else {
				g.setColor(Color.GRAY);
			}
			g.drawLine(x, CommonUtil.roundToInt(y1), x, CommonUtil.roundToInt(y2));
			x++;
		}
	}

	/**
	 * set statistic. repaints diagram.
	 */
	public synchronized void setStatistic(final List<Double> statistic) {
		this.statistic = statistic;
		mouseOverX = -1;
		repaint();
	}
	
}
